<?php
/**
 * Created by PhpStorm.
 * User: ari
 * Date: 10/8/14
 * Time: 6:56 PM
 */
namespace BC\Games\Holdem;

use BC\Games\Holdem\Exceptions\InsufficientFundsException;
use CPath\Data\Map\IKeyMap;
use CPath\Data\Map\IKeyMapper;

class HoldemPlayerOLD implements IKeyMap
{
	const FLAG_BUTTON =         0x01;
	const FLAG_SMALL_BLIND =    0x02;
	const FLAG_BIG_BLIND =      0x04;

	const FLAG_FOLDED =         0x10;
	const FLAG_CALLED =         0x20;
	const FLAG_SKIP_TURN =      0x40;

//	const FLAG_CHECKED =        0x20;
//	const FLAG_RAISED =         0x40;
//	const FLAG_ALL_IN =         0x80;

//	const FLAG_CAN_BET =        0x20;
//	const FLAG_CAN_STAY =       0x40;
//	const FLAG_CAN_FOLD =       0x80;

	const KEY_ID = 'id';
	const KEY_FLAGS = 'flags';
	const KEY_BALANCE = 'balance';
	const KEY_BET = 'bet';
	const KEY_DIFF = 'diff';

	private $mData;

	public function __construct(Array &$data) {
		$this->mData = &$data;
	}

	/**
	 * Get player ID
	 * @return string
	 */
	public function getID() {
		return $this->mData[self::KEY_ID];
	}

	public function getBalance() {
		return $this->mData[self::KEY_BALANCE];
	}

	public function clearBet() {
		unset(
			$this->mData[self::KEY_DIFF],
			$this->mData[self::KEY_BET]
		);
	}

	public function setBet($amount) {
		$old = $this->getBetAmount();
		if($amount <= $old)
			throw new InsufficientFundsException("Bet amount must be higher than previous amount");

		if($this->mData[self::KEY_BALANCE] < $amount)
			throw new InsufficientFundsException("Player does not have enough funds for this bet");

		$this->mData[self::KEY_BET] = $amount;
	}

	public function getBetAmount() {
		return isset($this->mData[self::KEY_BET]) ? $this->mData[self::KEY_BET] : 0;
	}

	public function getRemainingBetAmount() {
		$diff = isset($this->mData[self::KEY_DIFF]) ? $this->mData[self::KEY_DIFF] : 0;
		if($diff > 0)
			throw new \InvalidArgumentException("Winning player does not have a remaining bet amount");
		$amount = $this->getBetAmount() + $diff;
		if($amount < 0)
			throw new \InvalidArgumentException("Player did not bet " . $this->getBetAmount());
		return $amount;
	}

	public function clearRemainingBetAmount() {
		$this->mData[self::KEY_DIFF] = 0;
	}

	public function isAllIn() {
		return $this->getBetAmount() === $this->getBalance();
	}

	public function hasFolded() {
		return $this->hasFlag(self::FLAG_FOLDED);
	}

	public function isActionable($currentBetAmount, &$reason=null) {
		if($this->hasFlag(self::FLAG_SKIP_TURN))
			$reason = 'Player has skipped this turn';

		elseif($this->hasFolded())
			$reason = 'Player has folded';

		elseif($this->isAllIn())
			$reason = 'Player is all in';

		elseif($this->hasFlag(self::FLAG_CALLED)
			&& $this->getBetAmount() >= $currentBetAmount)
			$reason = 'Player has called and bet is at or above current bet';

		else
			return true;

		return false;
	}

	public function winBet($amount) {
		$this->mData[self::KEY_BALANCE] += $amount;
		if(!isset($this->mData[self::KEY_DIFF]))
			$this->mData[self::KEY_DIFF] = 0;
		$this->mData[self::KEY_DIFF] += $amount;
	}

	public function loseBet($amount) {
		$this->mData[self::KEY_BALANCE] -= $amount;
		if(!isset($this->mData[self::KEY_DIFF]))
			$this->mData[self::KEY_DIFF] = 0;
		$this->mData[self::KEY_DIFF] -= $amount;
		$this->getRemainingBetAmount();
//		if(-$this->mData[self::KEY_DIFF] > $this->getBetAmount())
//			throw new \InvalidArgumentException("Player does not have {$amount} to lose");
	}

	public function getFlags() {
		return $this->mData[self::KEY_FLAGS];
	}

	public function setFlag($flag, $_flag=null) {
		foreach(func_get_args() as $flag)
			$this->mData[self::KEY_FLAGS] |= $flag;
	}

	public function clearFlag($flag, $_flag=null) {
		foreach(func_get_args() as $flag)
			$this->mData[self::KEY_FLAGS] &= ~$flag;
	}

	public function getData() {
		return $this->mData;
	}

	/**
	 * Test values for one or more flags
	 * @param String $_flag vararg of flags.
	 * ->hasFlag(FLAG1 | FLAG2, FLAG3) returns true IF (either FLAG1 OR FLAG2 is set) AND (FLAG3 is set)
	 * @return bool
	 */
	function hasFlag($_flag) {
		foreach(func_get_args() as $arg)
			if(!($arg & $this->mData[self::KEY_FLAGS]))
				return false;

		return true;
	}

	/**
	 * Map data to the key map
	 * @param IKeyMapper $Map the map inst to add data to
	 * @internal param \CPath\Request\IRequest $Request
	 * @internal param \CPath\Request\IRequest $Request
	 * @return void
	 */
	function mapKeys(IKeyMapper $Map) {
		foreach($this->mData as $key=>$value)
			$Map->map($key, $value);
	}

	function __toString() {
		return $this->getID();
	}

	// Static

	static function create($playerID, $balance) {
		$data = array(
			self::KEY_ID => $playerID,
			self::KEY_BALANCE => $balance,
			self::KEY_FLAGS => 0,
		);
		return new HoldemPlayerOLD($data);
	}
}

